After building a base Gentoo system using OpenRC, everything functioned as expected except audio output. Players like mpv
or ffplay
reported no errors, but no sound was produced. This wasn’t due to ALSA itself failing aplay -l
showed hardware devices, and /proc/asound/cards
was populated. The issue was absence of a sound server managing the userland routing...
On more guided distributions, something like pipewire-pulse
is pulled automatically by metapackages or profile defaults. Gentoo requires explicit configuration. I chose PipeWire without running the PulseAudio daemon, but kept compatibility via libpulse
.
The audio stack behavior depends heavily on USE flags. Here's the relevant setup:
# /etc/portage/make.conf USE="-qt5 -kde -telemetry X pulseaudio"
The global pulseaudio
USE flag is needed for packages like SDL2, libcanberra, or anything that links against libpulse
. However, I did not want the PulseAudio daemon to be built or installed.
To achieve that:
# /etc/portage/package.use/pulseaudio media-sound/pulseaudio -daemon
This disables the init/startup part of PulseAudio while keeping the client library. Simultaneously, I needed PipeWire to act as the actual sound server:
# /etc/portage/package.use/pipewire media-video/pipewire sound-server
Executed the following:
emerge --ask media-video/pipewire emerge --ask media-video/wireplumber emerge --ask sys-auth/rtkit
wireplumber
is necessary as the session manager. Without it, PipeWire’s services start but remain inert, no nodes are created, and no audio routing occurs. rtkit
provides real-time priority handling, which is required by PipeWire to set thread priorities via SCHED_RR
. On OpenRC, this is not automatically available unless rtkit
is present and its service started.
Also added the user to the pipewire
group:
usermod -aG pipewire rian
Although not always necessary, some setups especially with custom PAM or seatd
handling benefit from explicit group permissions.
PipeWire’s default configuration is located in /usr/share/pipewire
. To allow for user-specific overrides:
mkdir -p ~/.config/pipewire/ cp /usr/share/pipewire/pipewire.conf ~/.config/pipewire/
System-wide:
cp /usr/share/pipewire/pipewire.conf /etc/pipewire/
If using pipewire-pulse
, it binds to $XDG_RUNTIME_DIR/pipewire-0
and creates a Pulse-compatible socket at $XDG_RUNTIME_DIR/pulse/native
. That’s how programs linked against libpulse
are transparently routed to PipeWire without reconfiguration.
You can confirm this by:
pactl info
Which should report: Server Name: PulseAudio (on PipeWire X.Y.Z)
PipeWire does not provide native OpenRC scripts. I created a local init file in /etc/init.d/pipewire
, wrapping pipewire
and pipewire-pulse
, then added it to default:
rc-update add pipewire default
Alternatively, one can manage it via per-user autostart if running a desktop session, especially under X or Wayland.
With this configuration, PipeWire serves as the active sound server, replacing the PulseAudio daemon entirely. libpulse
is still available for compatibility, but no extra daemon is launched. The system remains minimal, controlled, and fully functional in audio without systemd or extraneous layers.